﻿using Sidvall.CodeGenerator.Collections;
using System.Linq;

namespace Sidvall.CodeGenerator
{
    public class DomainObjectCollection : System.Collections.ObjectModel.KeyedCollection<string, DomainObject>
    {
        #region Business Members

        #region AddOrGetExisting

        public DomainObject AddOrGetExisting(DomainObject item)
        {
            if (item == null)
                return null;
            if (!Contains(item.FullName))
            {
                Add(item);
                return item;
            }
            return this[item.FullName];
        }

        #endregion
        #region ClearCache

        public void ClearCache()
        {
            foreach (var item in this)
                item.ClearCache();
            this.PropertyNames = null;
        }

        #endregion
        #region FindByName

        public DomainObject FindByName(string name)
        {
            return FindByName(name, null);
        }
        public DomainObject FindByName(string name, string @namespace)
        {
            name = DomainObject.GetFullName(@namespace, name);
            if (Contains(name))
                return this[name];
            return null;
        }

        #endregion
        #region GetKeyForItem

        protected override string GetKeyForItem(DomainObject item)
        {
            if (item == null)
                throw new System.ArgumentNullException("item");

            return item.FullName;
        }

        #endregion
        #region Import

        public void Import(System.Collections.Generic.IEnumerable<DomainObject> items)
        {
            if (items == null)
                return;

            foreach (var item in items)
            {
                if (Contains(item.Name))
                    this[item.Name].Import(item);
                else
                    Add(item);
            }
        }

        #endregion
        #region InsertItem

        protected override void InsertItem(int index, DomainObject item)
        {
            if ((item != null) && (this.DomainModel != null))
                item.DomainModel = this.DomainModel;
            base.InsertItem(index, item);
        }

        #endregion
        #region InitializeItemsLayers

        public void InitializeItemsLayers(bool? hasSqliteDataLayer, bool? hasUILayer, bool? hasWebLayer, bool? hasWebApiLayer, params string[] names)
        {
            var index = names.ToHashSet(o => DomainObject.GetFullName(null, o), true);
            foreach (var item in this)
            {
                if ((index != null) && (index.Contains(item.FullName)))
                {
                    InitializeItemsLayers(item, hasSqliteDataLayer, hasUILayer, hasWebLayer, hasWebApiLayer);
                }
            }
        }

        #endregion
        #region InitializeAllItemsLayers

        public void InitializeAllItemsLayers(bool? hasSqliteDataLayer, bool? hasUILayer, bool? hasWebLayer, bool? hasWebApiLayer, params string[] excludedNames)
        {
            var index = excludedNames.ToHashSet(o => DomainObject.GetFullName(null, o), true);
            foreach (var item in this)
            {
                if ((index == null) || (!index.Contains(item.FullName)))
                {
                    InitializeItemsLayers(item, hasSqliteDataLayer, hasUILayer, hasWebLayer, hasWebApiLayer);
                }
            }
        }

        #endregion
        #region RemoveItems

        public void RemoveItems(bool isDatabaseOnly, params string[] names)
        {
            if (names == null)
                return;
            foreach (var name in names)
            {
                var item = FindByName(name);
                if (item != null)
                {
                    if (isDatabaseOnly)
                        item.IsDatabaseOnly = true;
                    else
                        Remove(item);
                }
            }
        }

        #endregion
        #region RemoveAllItems

        public string[] RemoveAllItems(bool isDatabaseOnly, params string[] excludedNames)
        {
            var removedItemNames = new System.Collections.Generic.List<string>();
            var index = excludedNames.ToHashSet(o => DomainObject.GetFullName(null, o), true);
            var iMax = this.Count;
            for (int i = iMax - 1; i >= 0; i--)
            {
                var item = this[i];
                if ((index == null) || (!index.Contains(item.FullName)))
                {
                    if (isDatabaseOnly)
                        item.IsDatabaseOnly = true;
                    else
                        Remove(item);
                    removedItemNames.Add(item.FullName);
                }
            }
            return removedItemNames.ToArray();
        }

        #endregion
        #region RemoveRelationsByDomainObjectNames

        public void RemoveRelationsByDomainObjectNames(bool isDatabaseOnly, params string[] domainObjectNames)
        {
            foreach (var item in this)
                item.RemoveRelationsByDomainObjectNames(isDatabaseOnly, domainObjectNames);
        }

        #endregion
        #region SetItem

        protected override void SetItem(int index, DomainObject item)
        {
            if ((item != null) && (this.DomainModel != null))
                item.DomainModel = this.DomainModel;
            base.InsertItem(index, item);
        }

        #endregion
        #region PropertyNames

        private System.Collections.Generic.HashSet<string> _PropertyNames;
        public System.Collections.Generic.HashSet<string> PropertyNames
        {
            get
            {
                if (_PropertyNames == null)
                {
                    _PropertyNames = new System.Collections.Generic.HashSet<string>(System.StringComparer.OrdinalIgnoreCase);
                    foreach (var item in this)
                    {
                        var values = (from o in item.Properties
                                      select o.Name);
                        foreach (var value in values)
                        {
                            if (!_PropertyNames.Contains(value))
                                _PropertyNames.Add(value);
                        }
                    }
                }
                return _PropertyNames;
            }
            private set
            {
                _PropertyNames = value;
            }
        }

        #endregion

        #endregion
        #region Private Members

        #region DomainModel

        private DomainModel _DomainModel;
        private DomainModel DomainModel
        {
            get
            {
                return _DomainModel;
            }
            set
            {
                _DomainModel = value;
                foreach (var item in this)
                    item.DomainModel = value;
            }
        }

        #endregion

        #region InitializeItemsLayers

        private void InitializeItemsLayers(DomainObject item, bool? hasSqliteDataLayer, bool? hasUILayer, bool? hasWebLayer, bool? hasWebApiLayer)
        {
            if (hasSqliteDataLayer != null)
                item.HasSqliteDataLayer = hasSqliteDataLayer.Value;
            if (hasUILayer != null)
                item.HasUILayer = hasUILayer.Value;
            if (hasWebLayer != null)
                item.HasWebLayer = hasWebLayer.Value;
            if (hasWebApiLayer != null)
                item.HasWebApiLayer = hasWebApiLayer.Value;
        }

        #endregion
        #region SetDomainModel

        internal void SetDomainModel(DomainModel item)
        {
            this.DomainModel = item;
        }

        #endregion

        #endregion
        #region Constructors

        public DomainObjectCollection()
            : base(System.StringComparer.OrdinalIgnoreCase)
        {
        }

        #endregion
    }
}
